﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Raven.Client.Document;
using System.Windows.Forms;

namespace mrp16062010
{
    class Calistir
    {
        public string Id { get; set; }
        public int CalismaId { get; set; }
        public Uretec.UrunAgaciTipi secilenUrunAgaci;
        public Uretec.Aralik secilenSiparisBuyuklugu;
        public Uretec.Aralik secilenGunlukSiparisAraligi;
        public Uretec.Aralik secilenTeslimAraligi;
        public Simulation.Kuyruk.IslemTipi secilenKuyrukTipi;
        public TimeSpan secilenIsEmriAraligi;
        public Tarih anaAralik;
        Uretec.AralikSaat calismaSaatleri;
        public List<Siparis> siparisList;
        public List<Rota.RotaParcasi> parcaList;
        public Cizelge cizelge;
        Cizelge cizelgeBiten;
        public int CalismaNo { get; set; }
        Zamanlayici zamanlayici;
        public TimeSpan SimilasyonCalismaAraligi { get; set; }
        private Simulation.Ortam ortamSimilasyon;
        private List<IsParcasi> TatilList;
        public List<Uretec.AralikSaat> TatilAraliklari { get; set; }
        public Simulation.Ortam OrtamSimilasyon
        {
            get { return ortamSimilasyon; }
            set { ortamSimilasyon = value; }
        }
        public int kSabiti;
        public bool kKullan;
        public Calistir(List<Rota.RotaParcasi> gelenParcalar,
                        List<Siparis> gelenSiparisler,
                        Uretec.UrunAgaciTipi gelenUrunAgaci,
                        Uretec.Aralik gelenSiparisBuyuklugu,
                        Uretec.Aralik gelenTeslimAraligi,
                        Uretec.Aralik gelenGunlukSiparisAraligi,
                        Simulation.Kuyruk.IslemTipi gelenKuyrukTipi,
                        TimeSpan gelenIsEmriAraligi,
                        Tarih gelenAnaAralik,
                        Uretec.AralikSaat gelenCalismaSaatleri,
                        List<Uretec.AralikSaat> gelenTatilAraliklari,
                        int calismaNo,
                        int gelenkSabiti,
                        bool gelenKKulan)
        {
            CalismaNo = calismaNo;
            kSabiti = gelenkSabiti;
            kKullan = gelenKKulan;
            secilenUrunAgaci = gelenUrunAgaci;
            secilenSiparisBuyuklugu = gelenSiparisBuyuklugu;
            secilenGunlukSiparisAraligi = gelenGunlukSiparisAraligi;
            secilenTeslimAraligi = gelenTeslimAraligi;
            secilenKuyrukTipi = gelenKuyrukTipi;
            secilenIsEmriAraligi = gelenIsEmriAraligi;
            anaAralik = gelenAnaAralik;
            calismaSaatleri = gelenCalismaSaatleri;
            TatilAraliklari = gelenTatilAraliklari;
            cizelge = new Cizelge();

            cizelgeBiten = new Cizelge();
            //Ortamı Hazırla
            ortamSimilasyon = new Simulation.Ortam();
            ortamSimilasyon.KuyrukSiralamaTipi = secilenKuyrukTipi;
            ortamSimilasyon.BaslangicTarihi = anaAralik.BaslangicTarihi;
            SimilasyonCalismaAraligi = gelenIsEmriAraligi;


            parcaList = gelenParcalar;

            siparisList = gelenSiparisler;
            Tarih tatilTarihleri = new Tarih();
            tatilTarihleri.BaslangicTarihi = anaAralik.BaslangicTarihi;
            tatilTarihleri.BitisTarihi = new DateTime(2013, 12, 30);
            Uretec.TatilUret tatilUret = new Uretec.TatilUret(TatilAraliklari, calismaSaatleri, tatilTarihleri);
            TatilList = tatilUret.Olustur();
            cizelge.TatilEkle(TatilList);
            //Bu calismayı kaydet
            VeriBaslat();

            //
            //Ürün ağacını kaydet
            VeriUrunAgaci();

            //Siparişleri Kaydet
            VeriSiparis();
        }

        public Calistir(
            Uretec.UrunAgaciTipi gelenUrunAgaci,
            Uretec.Aralik gelenSiparisBuyuklugu,
            Uretec.Aralik gelenTeslimAraligi,
            Uretec.Aralik gelenGunlukSiparisAraligi,
            Simulation.Kuyruk.IslemTipi gelenKuyrukTipi,
            TimeSpan gelenIsEmriAraligi,
            Tarih gelenAnaAralik,
            Uretec.AralikSaat gelenCalismaSaatleri,
            List<Uretec.AralikSaat> gelenTatilAraliklari,
            int calismaNo
            )
        {
            CalismaNo = calismaNo;
            secilenUrunAgaci = gelenUrunAgaci;
            secilenSiparisBuyuklugu = gelenSiparisBuyuklugu;
            secilenGunlukSiparisAraligi = gelenGunlukSiparisAraligi;
            secilenTeslimAraligi = gelenTeslimAraligi;
            secilenKuyrukTipi = gelenKuyrukTipi;
            secilenIsEmriAraligi = gelenIsEmriAraligi;
            anaAralik = gelenAnaAralik;
            calismaSaatleri = gelenCalismaSaatleri;
            TatilAraliklari = gelenTatilAraliklari;
            cizelge = new Cizelge();
            
            cizelgeBiten = new Cizelge();
            //Ortamı Hazırla
            ortamSimilasyon = new Simulation.Ortam();
            ortamSimilasyon.KuyrukSiralamaTipi = secilenKuyrukTipi;
            ortamSimilasyon.BaslangicTarihi = anaAralik.BaslangicTarihi;
            SimilasyonCalismaAraligi = Ayarlar.Nesne.SimilasyonCalismaAraligi;
            BilgileriHazirla();
        }


        private void BilgileriHazirla()
        {
            Uretec.UrunAgaciUret agacUret = new Uretec.UrunAgaciUret();
            parcaList = agacUret.ListeUret(secilenUrunAgaci, 25);
            Uretec.SiparisUret siparisUret = Uretec.SiparisUret.Nesne;
            siparisUret.GunlukSiparisSayisi = secilenGunlukSiparisAraligi;
            siparisUret.SiparisBuyuklugu = secilenSiparisBuyuklugu;
            siparisUret.SiparisTeslimSuresi = secilenTeslimAraligi;
            siparisList = siparisUret.Uret(anaAralik, calismaSaatleri, parcaList);
            Tarih tatilTarihleri = new Tarih();
            tatilTarihleri.BaslangicTarihi = anaAralik.BaslangicTarihi;
            tatilTarihleri.BitisTarihi = new DateTime(2013, 12, 30);
            Uretec.TatilUret tatilUret = new Uretec.TatilUret(TatilAraliklari, calismaSaatleri, tatilTarihleri);
            TatilList = tatilUret.Olustur();
            cizelge.TatilEkle(TatilList);
            //Bu calismayı kaydet
            VeriBaslat();
            //Siparişleri Kaydet
            VeriSiparis();
        }

        private List<Siparis> SiparisGetir(Tarih tarihAraligi)
        {
            List<Siparis> liste = (
                from x in siparisList
                where x.TarihBilgisi.BaslangicTarihi >= tarihAraligi.BaslangicTarihi
                 &&
                 x.TarihBilgisi.BaslangicTarihi < tarihAraligi.BitisTarihi
                orderby x.TarihBilgisi.BaslangicTarihi ascending
                select x
                                      ).ToList<Siparis>();
            if (kKullan == true)
            {
                foreach (Siparis item in liste)
                {
                    item.TWKHesapla(kSabiti);
                }
            }
            return liste;
        }
        List<Siparis> eklenen = new List<Siparis>();
        int debugsay = 0;
        public void Cizelgele(List<Siparis> siparisler)
        {
            //if (debugsay>0)
            //{
            //    return;
            //}
            foreach (Siparis item in siparisler)
            {
                if (!eklenen.Contains(item))
                {
                    //debugsay++;

                   Yukle yukle = new Yukle(cizelge, item);

                   //foreach (IsParcasi parca in item.IsParcalari)
                   //{
                   //    VeriIsParcasi(parca);
                   //}
                }
            }
        }

        private List<IsParcasi> CizelgedenParcaGetir(Tarih tarihAraligi)
        {
            var liste = new List<IsParcasi>();
            foreach (CizelgeIsMerkezi cim in cizelge.Merkezler)
            {
                if (cim.IsListe.FirstOrDefault() != null)
                {


                    var secilenParcalar = (from x in cim.IsListe
                                           where x.ArkasindakiIsParcalari.Count == 0 && x.TatilMi == false
                                           &&
                                           x.BasTarihi >= tarihAraligi.BaslangicTarihi && x.BasTarihi < tarihAraligi.BitisTarihi

                                           select x);
                    
                        liste.AddRange(secilenParcalar);
                    

                    //Bu satir siparis numarasina gore arkasinda parca olmayan (imalat) parcalarini secer
                    //
                    //var gruplanmisSiparisler = secilenParcalar.GroupBy(x => x.SiparisBilgi);
                    //foreach (var siparisGruptan in gruplanmisSiparisler)
                    //{
                    //    List<IsParcasi> tempList = siparisGruptan.Key.IsParcalari.Where(x => x.ArkasindakiIsParcalari.Count == 0).ToList();
                    //    liste.AddRange(tempList);
                    //}
                }
            }
            liste = liste.OrderBy(x => x.BasTarihi).ToList();
            // 
            return liste;
        }
        List<IsParcasi> eklenenSimParcalar = new List<IsParcasi>();
        private void SimuleEt(List<IsParcasi> parcaList)
        {
            List<IsParcasi> yl = parcaList.Except(eklenenSimParcalar).ToList<IsParcasi>();
            ortamSimilasyon.ParcaAta(yl);
        }

        public void Baslat()
        {
            zamanlayici = new Zamanlayici(Ayarlar.Nesne.SimilasyonCalismaAraligi, anaAralik);
            zamanlayici.HaberAraligi = secilenIsEmriAraligi;
            zamanlayici.Basladi += new Zamanlayici.BasladiHandler(zamanlayici_Basladi);
            zamanlayici.Ilerledi += new Zamanlayici.IlerlediHandler(zamanlayici_Ilerledi);
            zamanlayici.AralikBitti += new Zamanlayici.AralikBittiHandler(zamanlayici_AralikBitti);
            zamanlayici.Bitti += new Zamanlayici.BittiHandler(zamanlayici_Bitti);
            zamanlayici.GunlukAralik += new Zamanlayici.GunlukAralikHandler(zamanlayici_GunlukAralik);
            zamanlayici.Baslat();
            /*for (DateTime date = anaAralik.BaslangicTarihi; date <= anaAralik.BitisTarihi; date = date.AddDays(secilenIsEmriAraligi))
            {
                Tarih aralik = new Tarih(date, date.AddDays(secilenIsEmriAraligi));
                zamanlayici.CalismaTarihleri = aralik;
            }*/
        }

        void zamanlayici_GunlukAralik(object o, EventArgs e)
        {
            if (!Ayarlar.Nesne.VeriKaydiAcik)
            {
                return;
            }
            db.SaveChanges();
        }

        void zamanlayici_Bitti(object o, EventArgs e)
        {
            VeriGuncelle();
            Console.Out.WriteLine("Bitti");

            //Data.Kaydedici kaydet = new Data.Kaydedici(this);
           
            this.ortamSimilasyon.Ortalamalar.Clear();
            this.ortamSimilasyon = null;
            this.parcaList = null;
            this.siparisList.Clear();
            this.TatilList = null;
            
            Console.Out.WriteLine("Kaydedildi");
            //MessageBox.Show("Tamam");
            if (Bitti != null)
            {
                Bitti(this, new EventArgs());
            }
            /*
            var store = new DocumentStore { Url = "http://localhost:8080" };
            ortamSimilasyon.Id = "ortam";
            store.Initialize();
            var session = store.OpenSession();
            session.Store(this.ortamSimilasyon);
            
            session.SaveChanges();
            session.Store(this.siparisList);
            session.SaveChanges();*/
        }

        void zamanlayici_Ilerledi(object o, EventArgs e)
        {
            Zamanlayici zam = ((Zamanlayici)o);
            Tarih yeniAralik = new Tarih(zam.Tarih-zam.CalismaAraligi, zam.Tarih);
            List<Siparis> Siparisler = SiparisGetir(yeniAralik);
            if (Siparisler.Count>0)
            {
               Cizelgele(Siparisler);
               eklenen.AddRange(Siparisler);
            }
            
            //Tarih simAralik = new Tarih(zam.Tarih - zam.CalismaAraligi, zamanlayici.Tarih.Add(secilenIsEmriAraligi));
            List<IsParcasi> parcalar = CizelgedenParcaGetir(IsEmriAralik);
            if (parcalar.Count>0)
            {
                
              SimuleEt(parcalar);
              eklenenSimParcalar.AddRange(parcalar);
            }
            
            //burada secilenIsEmriAraligi değeri kadar zamanlayıcı ilerlediyse planlayıcıyı çalıştır sonra devam ettir
            ortamSimilasyon.Tetikle(zam.Tarih);
            if (zam.Tarih.TatilMi()==false)
            {
                VeriOrtalama(ortamSimilasyon.Ortalama);
            }
            
        }

        Tarih IsEmriAralik = new Tarih();

        void zamanlayici_AralikBitti(object o, EventArgs e)
        {
            Console.Out.WriteLine(DateTime.Now.ToString() + " Sim. Tarihi:" + ((Zamanlayici)o).Tarih.ToString());
            IsEmriAralik = new Tarih(zamanlayici.Tarih, zamanlayici.Tarih.Add(secilenIsEmriAraligi));
            //Burada bir sonraki aralık için cizelgeleme çalıştırılır.
            //zamanlayici.Durdur();
            /*Tarih yeniAralik = new Tarih(zamanlayici.Tarih, zamanlayici.Tarih.Add(secilenIsEmriAraligi));
            List<Siparis> Siparisler = SiparisGetir(yeniAralik);
            Cizelgele(Siparisler);
            List<IsParcasi> parcalar = CizelgedenParcaGetir(yeniAralik);
            SimuleEt(parcalar);*/
        }

        void zamanlayici_Basladi(object o, EventArgs e)
        {
            IsEmriAralik.BaslangicTarihi = zamanlayici.Tarih;
            IsEmriAralik.BitisTarihi = zamanlayici.Tarih.Add(secilenIsEmriAraligi);
            Tarih yeniAralik = new Tarih(zamanlayici.Tarih, zamanlayici.Tarih);
            List<Siparis> Siparisler = SiparisGetir(yeniAralik);
            if (Siparisler.Count > 0)
            {
                Cizelgele(Siparisler);
            }
            
            foreach (IsMerkezi merkez in cizelge.IsMerkezleri)
            {
                Simulation.Makine yeniMakine = new Simulation.Makine();
                yeniMakine.Merkez = merkez;
                yeniMakine.BulunduguOrtam = ortamSimilasyon;
                yeniMakine.Kod = merkez.Kod;
                ortamSimilasyon.MakineEkle(yeniMakine);
                yeniMakine.Cikti += new Simulation.Makine.CiktiHandler(yeniMakine_Cikti);
            }
            VeriMakine();
            ortamSimilasyon.TatilAta(TatilList);
            ortamSimilasyon.ParcaAta(CizelgedenParcaGetir(yeniAralik));
                /*
            Tarih yeniAralik = new Tarih(zamanlayici.Tarih, zamanlayici.Tarih.Add(secilenIsEmriAraligi));
            List<Siparis> Siparisler = SiparisGetir(yeniAralik);
            Cizelgele(Siparisler);
            foreach (IsMerkezi merkez in cizelge.IsMerkezleri)
            {
                Simulation.Makine yeniMakine = new Simulation.Makine();
                yeniMakine.Merkez = merkez;
                yeniMakine.BulunduguOrtam = ortamSimilasyon;
                yeniMakine.Kod = merkez.Kod;
                ortamSimilasyon.MakineEkle(yeniMakine);
            }
            ortamSimilasyon.TatilAta(TatilList);
            ortamSimilasyon.ParcaAta(CizelgedenParcaGetir(yeniAralik));*/
        }

        void yeniMakine_Cikti(object o, IsParcasi cikan, EventArgs e)
        {
            VeriIsParcasi(cikan);
        }

        Data.simulasyonEntities db = new Data.simulasyonEntities();

        private void VeriBaslat()
        {
            if (!Ayarlar.Nesne.VeriKaydiAcik)
            {
                return;
            }
            Data.Calisma calisma = new Data.Calisma();
            calisma.CalismaNo = this.CalismaNo;
            calisma.IsEmriAraligi = this.secilenIsEmriAraligi.Days;
            calisma.SiralamaKurali = (int)this.secilenKuyrukTipi;
            calisma.UrunAgaciTipi = this.secilenUrunAgaci.Id;
            calisma.KDegeri = this.kSabiti;
            db.AddToCalisma(calisma);
            db.SaveChanges();
            int calismaId = calisma.Id;
            this.CalismaId = calismaId;
        }

        private void VeriGuncelle()
        {
            if (!Ayarlar.Nesne.VeriKaydiAcik)
            {
                return;
            }
            //int siparisno = 0;
            foreach (Siparis sip in this.siparisList)
            {
                //siparisno++;
                Data.Siparis siparis = (from x in db.Siparis
                                        where x.Id == sip.Id
                                        select x).SingleOrDefault();
                siparis.Adet = sip.Adet;
                siparis.CalismaId = this.CalismaId;
                siparis.CizBasTarihi = sip.PlanlamaTarihleri.BaslangicTarihi.Sql();
                siparis.CizBitTarihi = sip.PlanlamaTarihleri.BitisTarihi.Sql();
                siparis.GelisTarihi = sip.TarihBilgisi.BaslangicTarihi.Sql();
                siparis.SonTarih = sip.TarihBilgisi.BitisTarihi.Sql();
                siparis.SimBasTarihi = sip.SimilasyonTarihleri.BaslangicTarihi.Sql();
                siparis.SimBitTarihi = sip.SimilasyonTarihleri.BitisTarihi.Sql();
                //siparis.SiparisNo = siparisno;

                db.SaveChanges();
            }

            foreach (Simulation.Makine makine in this.ortamSimilasyon.MakineList)
            {
                Data.Makine mak = (from x in db.Makine
                                   where x.Id == makine.Id
                                   select x).FirstOrDefault();
                if (mak != null)
                {
                    mak.CalismaSuresi = Convert.ToInt32(makine.CalismaSuresi.TotalMinutes);
                    db.SaveChanges();
                }
            }
        }

        private void VeriSiparis()
        {
            if (!Ayarlar.Nesne.VeriKaydiAcik)
            {
                return;
            }
            int siparisno = 0;
            foreach (mrp16062010.Siparis sip in this.siparisList)
            {
                siparisno++;
                Data.Siparis siparis = new Data.Siparis();
                siparis.Adet = sip.Adet;
                siparis.CalismaId = this.CalismaId;
                siparis.CizBasTarihi = sip.PlanlamaTarihleri.BaslangicTarihi.Sql();
                siparis.CizBitTarihi = sip.PlanlamaTarihleri.BitisTarihi.Sql();
                siparis.GelisTarihi = sip.TarihBilgisi.BaslangicTarihi.Sql();
                siparis.SonTarih = sip.TarihBilgisi.BitisTarihi.Sql();
                siparis.SimBasTarihi = sip.SimilasyonTarihleri.BaslangicTarihi.Sql();
                siparis.SimBitTarihi = sip.SimilasyonTarihleri.BitisTarihi.Sql();
                siparis.SiparisNo = siparisno;
                siparis.RotaNo = sip.Rota.Id;
                db.AddToSiparis(siparis);
                db.SaveChanges();
                int siparisId = siparis.Id;
                sip.Id = siparisId;
            }
        }

        private void VeriMakine()
        {
            if (!Ayarlar.Nesne.VeriKaydiAcik)
            {
                return;
            }
            foreach (Simulation.Makine mak in this.OrtamSimilasyon.MakineList)
            {
                Data.Makine m = new Data.Makine();
                m.Ad = mak.Kod.ToString();
                m.CalismaId = this.CalismaId;
                //m.K=mak.Kod
                m.CalismaSuresi = Convert.ToInt32(mak.CalismaSuresi.TotalMinutes);
                db.AddToMakine(m);
                db.SaveChanges();
                mak.Id = m.Id;
            }
        }

        private void VeriOrtalama(Simulation.KuyrukOrtalama ort)
        {
            if (!Ayarlar.Nesne.VeriKaydiAcik)
            {
                return;
            }
            Data.Kuyruk k = new Data.Kuyruk();
            k.Adet = ort.OrtalamaAdet;
            k.CalismaId = this.CalismaId;
            k.Tarih = ort.Tarih.Sql();
            k.Uzunluk = Convert.ToInt32(ort.OrtalamaUzunluk.TotalMinutes);
            k.WIP = ort.WIP;
            db.AddToKuyruk(k);
        }

        private void VeriIsParcasi(IsParcasi parca)
        {
            
            if (!Ayarlar.Nesne.VeriKaydiAcik)
            {
                return;
            }
            Data.IsParcasi p = new Data.IsParcasi();
            p.ArkasindakiParcaSayisi = parca.ArkasindakiIsParcalari.Count;
            
            p.CalismaId = this.CalismaId;
            
            p.CizelgeBaslangic = parca.BasTarihi.Sql();
            p.CizelgeBitis = parca.BitTarihi.Sql();
            p.IslemGiris = parca.SimulasyonBilgisi.IslemeTarihi.BaslangicTarihi.Sql();
            p.IslemCikis = parca.SimulasyonBilgisi.IslemeTarihi.BitisTarihi.Sql();
            p.KuyrukGiris = parca.SimulasyonBilgisi.GirisBeklemeTarihi.BaslangicTarihi.Sql();
            p.KuyrukCikis = parca.SimulasyonBilgisi.GirisBeklemeTarihi.BitisTarihi.Sql();
            p.MakineNo = parca.IM.Kod;
            p.SiparisId = parca.SiparisBilgi.Id;//siparisId;
            p.Uzunluk = Convert.ToInt32(parca.Uzunluk.TotalMinutes);
            p.YuklemeTipi = Convert.ToByte(parca.YuklemeTipi);
            if (parca.OnundekiIsParcasi==null)
            {
                p.SonParcaMi = 1;
            }
            db.AddToIsParcasi(p);
            db.SaveChanges();
            parca.Id = p.Id;
            //Bu yeni eklenen parcanın arkasındaki parçalarının önündeki parça IDsini güncelle
            foreach (IsParcasi arkadakiParca in parca.ArkasindakiIsParcalari)
            {
                Data.IsParcasi arkadakiParVeri = (from x in db.IsParcasi
                                                  where x.Id == arkadakiParca.Id
                                                  select x).FirstOrDefault();
                if (arkadakiParVeri!=null)
                {
                    arkadakiParVeri.OnundekiParcaId = parca.Id;
                    db.SaveChanges();
                }
            }
        }

        private void VeriUrunAgaci()
        {
            if (!Ayarlar.Nesne.VeriKaydiAcik)
            {
                return;
            }
            foreach (Rota.RotaParcasi parca in parcaList)
            {
                Data.UrunAgaci agac = new Data.UrunAgaci();
                agac.CalismaId = this.CalismaId;
                agac.Numara = parca.Kod;
                agac.Tip = secilenUrunAgaci.Ad;
                db.AddToUrunAgaci(agac);
                db.SaveChanges();
                parca.Id = agac.Id;
            }
        }

        public delegate void BittiHandler(object o, EventArgs e);

        public event BittiHandler Bitti;
        

        protected virtual void OnBitti(object o, EventArgs e)
        {
            if (Bitti != null)
            {
                Bitti(o, e);
            }
        }

    }

}